<template>
    <view class="">
        <view class="u-sticky-wrap" :class="[elClass]" :style="{
            height: fixed ? height + 'px' : 'auto',
            backgroundColor: bgColor
        }">
            <view class="u-sticky" :style="{
                position: fixed ? 'fixed' : 'static',
                top: stickyTop + 'px',
                left: left + 'px',
                width: width == 'auto' ? 'auto' : width + 'px',
                zIndex: uZIndex
            }">
                <slot></slot>
            </view>
        </view>
    </view>
</template>

<script>
    /**
     * sticky 吸顶
     * @description 该组件与CSS中position: sticky属性实现的效果一致，当组件达到预设的到顶部距离时， 就会固定在指定位置，组件位置大于预设的顶部距离时，会重新按照正常的布局排列。
     * @tutorial https://www.uviewui.com/components/sticky.html
     * @property {String Number} offset-top 吸顶时与顶部的距离，单位rpx（默认0）
     * @property {String Number} index 自定义标识，用于区分是哪一个组件
     * @property {Boolean} enable 是否开启吸顶功能（默认true）
     * @property {String} bg-color 组件背景颜色（默认#ffffff）
     * @property {String Number} z-index 吸顶时的z-index值（默认970）
     * @property {String Number} h5-nav-height 导航栏高度，自定义导航栏时(无导航栏时需设置为0)，需要传入此值，单位px（默认44）
     * @event {Function} fixed 组件吸顶时触发
     * @event {Function} unfixed 组件取消吸顶时触发
     * @example <u-sticky offset-top="200"><view>塞下秋来风景异，衡阳雁去无留意</view></u-sticky>
     */
    export default {
        name: "u-sticky",
        props: {
            // 吸顶容器到顶部某个距离的时候，进行吸顶，在H5平台，NavigationBar为44px
            offsetTop: {
                type: [Number, String],
                default: 0
            },
            //列表中的索引值
            index: {
                type: [Number, String],
                default: ''
            },
            // 是否开启吸顶功能
            enable: {
                type: Boolean,
                default: true
            },
            // h5顶部导航栏的高度
            h5NavHeight: {
                type: [Number, String],
                default: 44
            },
            // 吸顶区域的背景颜色
            bgColor: {
                type: String,
                default: '#ffffff'
            },
            // z-index值
            zIndex: {
                type: [Number, String],
                default: ''
            }
        },
        data() {
            return {
                fixed: false,
                height: 'auto',
                stickyTop: 0,
                elClass: this.$u.guid(),
                left: 0,
                width: 'auto',
            };
        },
        watch: {
            offsetTop(val) {
                this.initObserver();
            },
            enable(val) {
                if (val == false) {
                    this.fixed = false;
                    this.disconnectObserver('contentObserver');
                } else {
                    this.initObserver();
                }
            }
        },
        computed: {
            uZIndex() {
                return this.zIndex ? this.zIndex : this.$u.zIndex.sticky;
            }
        },
        mounted() {
            this.initObserver();
        },
        methods: {
            initObserver() {
                if (!this.enable) return;
                // #ifdef H5
                this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.h5NavHeight : this.h5NavHeight;
                // #endif
                // #ifndef H5
                this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) : 0;
                // #endif

                this.disconnectObserver('contentObserver');
                this.$uGetRect('.' + this.elClass).then((res) => {
                    this.height = res.height;
                    this.left = res.left;
                    this.width = res.width;
                    this.$nextTick(() => {
                        this.observeContent();
                    });
                });
            },
            observeContent() {
                this.disconnectObserver('contentObserver');
                const contentObserver = this.createIntersectionObserver({
                    thresholds: [0.95, 0.98, 1]
                });
                contentObserver.relativeToViewport({
                    top: -this.stickyTop
                });
                contentObserver.observe('.' + this.elClass, res => {
                    if (!this.enable) return;
                    this.setFixed(res.boundingClientRect.top);
                });
                this.contentObserver = contentObserver;
            },
            setFixed(top) {
                const fixed = top < this.stickyTop;
                if (fixed) this.$emit('fixed', this.index);
                else if(this.fixed) this.$emit('unfixed', this.index);
                this.fixed = fixed;
            },
            disconnectObserver(observerName) {
                const observer = this[observerName];
                observer && observer.disconnect();
            },
        },
        beforeDestroy() {
            this.disconnectObserver('contentObserver');
        }
    };
</script>

<style scoped lang="scss">
    @import "../../libs/css/style.components.scss";
    
    .u-sticky {
        z-index: 9999999999;
    }
</style>
